#include "cio.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "../cominc/ctask.h"

/* 外部导入的<命令-回调>键值对列表 */
extern uint32_t CioTxBytes(const uint8_t* tx, uint32_t len);
extern const char* EXT_PKG_HEAD;

/* 弱实现控制台 */
int __attribute__((weak)) LOG(const char *initStr, ...) { return 0; }
int __attribute__((weak)) LOGCritcal(const char *initStr, ...) { return 0; }
int __attribute__((weak)) LogEvent(const char *initStr, ...) { return 0; }
void __attribute__((weak)) WaitUsrInput(void) { }

/* cio单例对象 */
typedef struct
{
    uint8_t *rxBuffer;
    uint8_t *txBuffer;
    uint32_t rxBufferLen;
    uint32_t txBufferLen;
    size_t head; // 环形队列头
    size_t tail; // 环形队列尾
    CioSta sta; // 环形队列状态
    uint8_t* rxMirrorBuf; // 队列镜像
    CioPair* cioList;
    size_t cioListLen;
} cioObj;
volatile static cioObj cio;

/* 内部实现方法 */
static void FlushRx(void); // 清除缓冲区
static FrmTransState CheckoutPkg(const uint8_t* data, size_t len);
int CioPopTask(const char *str, size_t len);

/* 外部接口方法 */
void CioInit(CioPair* cioList, int cioListLen)
{
    cio.cioList = cioList;
    cio.cioListLen = cioListLen;
    CioRegisterRx(NULL, NULL, 0);
    CioRegisterTx(NULL, 0);
    FlushRx();
}

void CioDump(void)
{
    LOG("\r\n-----CioDump-----");
    LOG("CioSta[%u]", cio.sta);
    LOG("RxBuffer[0x%08x] Len[%u]", cio.rxBuffer, cio.rxBufferLen);
    LOG("TxBuffer[0x%08x] Len[%u]", cio.txBuffer, cio.rxBufferLen);
    LOG("Rx head[%u] -> tail[%u]", cio.head, cio.tail);
    LOG("CioList: (%d in Total)", cio.cioListLen);
    for (size_t idx = 0; idx < cio.cioListLen; idx++) {
        const CioPair* task = cio.cioList + idx;
        LOG("cmdType[%2d] exeAddr[0x%08x]", task->cmd, task->task);
    }
}

int CioPrintRxBuffer(const char *str, size_t len)
{
    LOG("CioPrintRx");
    if (cio.head < cio.tail) {
        // 未发生回绕
        LOG("CioRx [0x%8x] -> [0x%8x]", cio.rxBuffer + cio.head, cio.rxBuffer + cio.tail);
        for (size_t idx = cio.head; idx < cio.tail; idx++) {
            LOG("%02x ", cio.rxBuffer[idx]);
            if (idx % 64) {
                LOG("");
            }
        }
    } else {
        // 发生回绕
        LOG("CioRx [0x%8x] -> [0x%8x]", cio.rxBuffer + cio.head, cio.rxBuffer + cio.tail);
        size_t idx;
        LOG("(head->end)");
        for (idx = cio.head; idx < cio.rxBufferLen; idx++) {
            LOG("%02x ", cio.rxBuffer[idx]);
            if (idx % 64) {
                LOG("");
            }
        }
        LOG("(reverse)");
        for (idx = 0; idx < cio.tail; idx++) {
            LOG("%02x ", cio.rxBuffer[idx]);
            if (idx % 64) {
                LOG("");
            }
        }
    }
		
		return 0;
}

void CioRegisterRx(uint8_t* rxBuffer, uint8_t* rxBufMirror, size_t rxLen)
{
    cio.rxBuffer = rxBuffer;
    cio.rxBufferLen = rxLen;
    cio.rxMirrorBuf = rxBufMirror; // 不需要环形队列时可以置为空
	  CioRstRx();
}

void CioRegisterTx(uint8_t *txBuffer, size_t txLen)
{
    cio.txBuffer = txBuffer;
    cio.txBufferLen = txLen;
}

/* 按照帧头划分rxbuffer后送入CioRxPkg处理，返回处理掉的字节数 */
uint32_t CioRxPkg(const uint8_t *pPkgData, size_t len)
{
		pkg* pPkg = (pkg*)pPkgData;
    if (len < pPkg->dataLen) {
        return 0; // 传输尚未完成，不做处理，也不出队
    }
    /* 加严校验 */
    FrmTransState frmCheckRet = CheckoutPkg(pPkgData, len);
    if (frmCheckRet != FRM_OK) {
				LOGCritcal("PkgErr: %u", frmCheckRet);
        return len;
    }
    /* 遍历各命令字的回调 */
    for (size_t idx = 0; idx < cio.cioListLen; idx++) {
        const CioPair* cioSlot = cio.cioList + idx;
        if (cioSlot->cmd == pPkg->type) {
            /* 向ctask中注册任务，ExeTask()中异步地回调 */
            RegTask(cioSlot->task, (const char*)pPkgData + PKG_DATA_OFFSET, pPkg->dataLen);
            break;
        }
    }
    return len;
}

uint32_t CioTxPkg(pkgType type, const void* src, uint32_t len)
{
    pkg o;
    memset(&o, 0, sizeof(pkg));
    o.type = type;
    o.dataLen = len;
    memcpy(o.head, EXT_PKG_HEAD, strlen(EXT_PKG_HEAD));
    const uint8_t* pRcc = NULL;
    for (pRcc = (const uint8_t*)&o; pRcc != (const uint8_t*)&o.data; pRcc++) {
        o.rcc += *pRcc;
    }
    for (pRcc = (const uint8_t*)src; pRcc != (const uint8_t*)(src) + len; pRcc++) {
        o.rcc += *pRcc;
    }
		size_t totalLen = PKG_DATA_OFFSET + len + sizeof(o.rcc);
    if (cio.txBuffer != NULL && cio.txBufferLen > totalLen) {
        memcpy(cio.txBuffer, (uint8_t*)&o, PKG_DATA_OFFSET);
        memcpy(cio.txBuffer + PKG_DATA_OFFSET, src, len);
        memcpy(cio.txBuffer + PKG_DATA_OFFSET + len, (const uint8_t*)&o.rcc, sizeof(o.rcc));
        CioTxBytes(cio.txBuffer, totalLen);
    } else {
        CioTxBytes((uint8_t*)&o, PKG_DATA_OFFSET);
        CioTxBytes(src, len);
        CioTxBytes((const uint8_t*)&o.rcc, sizeof(o.rcc));
    }
    return ERR_SUCCESS;
}

//uint32_t TxMakeRssiPkg(uint16_t *data, uint32_t len)
//{
//    pkg o;
//    memcpy(o.head, EXT_PKG_HEAD, strlen(EXT_PKG_HEAD));
//    o.type = READ_RSSI;
//    memset((uint8_t *)o.data, 0, sizeof(o.data));
//    pkgDataRssi rssiBody;
//    memset((uint8_t *)&rssiBody, 0, sizeof(rssiBody));
//    rssiBody.channelCnt = CH_MAX;
//    for (uint32_t cnt = 0; cnt < rssiBody.channelCnt; cnt++)
//    {
//        rssiBody.rssi[cnt] = data[cnt];
//    }
//    memcpy((uint8_t *)o.data, (uint8_t *)&rssiBody, sizeof(o.data));
//
//    uint32_t rcc = 0;
//    for (uint32_t cnt = 0; cnt < sizeof(pkg) - sizeof(uint32_t); cnt++)
//    {
//        rcc += ((uint8_t *)&o)[cnt];
//    }
//    o.rcc = rcc;
//    txPkg(o);
//
//    return ERR_SUCCESS;
//}

void FlushRx(void)
{
    memset(cio.rxBuffer, 0, cio.rxBufferLen);
}

#define STR_BUFF_SIZE 32
#define NUM_BASE_DEC 10
char *ic(uint32_t val)
{
    static char strBuff[STR_BUFF_SIZE];
    /* zerolize return buffer */
    memset(strBuff, 0, STR_BUFF_SIZE);
    /* string encode to stack */
    char strStack[STR_BUFF_SIZE] = {0};
    char *pStrStack = strStack;
    do
    {
        pStrStack++; // first byte as stack bottom ('\0')
        *pStrStack = '0' + val % NUM_BASE_DEC;
        val /= NUM_BASE_DEC;
    } while (val != 0 && pStrStack - strStack < STR_BUFF_SIZE);
    /* stack out to return */
    char *pStr = strBuff;
    while (*pStrStack != 0)
    {
        *pStr = *pStrStack;
        pStr++;
        pStrStack--;
    }

    return strBuff;
}

/* 环形队列维护 */
// 接收器为配置为换回的串口DMA接收器，接收到cio.buffer中
// 处理接收事件时，将回绕后的部分copy到cio.rxMirrorBuf 镜像区，
// 以一次拷贝的代价，能够按结构体声明解释帧内存，提升可读性
// 通过CioRxPkg向ctask注册两个回调任务：
//      1，待处理帧的帧内容，通过硬编码实现类似反射的机制
//      2. Cio环形队列的Pop任务
void CioRstRx(void)
{
    memset(cio.rxMirrorBuf, 0, cio.rxBufferLen);
    cio.sta = CIO_RDY;
}

CioSta CioPush(size_t pushLen)
{
    // 环形队列入队
    // 更新队列标志位
    cio.tail = (cio.tail + pushLen) % cio.rxBufferLen;
    if (cio.tail > cio.head) {
        // cio.sta = CIO_OVF;		// TODO:判断溢出
    }
    return GetCioSta();
}

void CioPop(size_t popLen)
{
    cio.head = (cio.head + popLen) % cio.rxBufferLen;
}

CioSta GetCioSta()
{
    return cio.sta;
}

uint8_t IsCioEmpty()
{
    return cio.tail == cio.head;
}

FrmTransState ProcCioRxEvent()
{
    if (cio.rxMirrorBuf == NULL || IsCioEmpty() || GetCioSta() != CIO_RDY) {
        return FRM_CIONRDY;
    }
    size_t rxLen;
    if (cio.tail > cio.head) {
        // 未发生回绕
        rxLen = cio.tail - cio.head;
    } else {
        // 缓冲区发生回绕，将回绕后的部分copy到cio.rxMirrorBuf 镜像区，以便按内存解释
        memcpy(cio.rxMirrorBuf, cio.rxBuffer, cio.tail);
        rxLen = cio.tail + (cio.rxBufferLen - cio.head);
    }
    size_t procedLen = CioRxPkg(cio.rxBuffer + cio.head, rxLen);
    if (procedLen == 0) {
        // 无完整可用帧，提前返回
        return FRM_ONGOING;
    }
    /* 注册相应的Pop任务 */
    RegTask(CioPopTask, NULL, procedLen);

    return FRM_OK;
}

int CioPopTask(const char *str, size_t len)
{
    if (cio.sta == CIO_OVF) {
				LOGCritcal("[CIO] CIO Overflow! Slower Commanding speed required.");
		}
    CioPop(len);
    return ERR_SUCCESS;
}

static FrmTransState CheckoutPkg(const uint8_t* data, size_t len)
{
    if (data == NULL || len < sizeof(pkg)) {
        LOGCritcal("data == NULL || len < sizeof(pkg) : len[%u], sizeof(pkg)[%u]", len, sizeof(pkg));
        return FRM_LENERR;
    }
    const pkg* o = (const pkg*)data;
    /* 校验帧头 */
    if (memcmp(o->head, EXT_PKG_HEAD, strlen(EXT_PKG_HEAD)) != 0) {
        LOGCritcal("type[%u] Head Error");
        return FRM_HEADERR;
    }
    /* 校验RCC */
    const uint8_t* dataAddr = data + PKG_DATA_OFFSET;
    uint32_t rccRcv = *((uint32_t*)(dataAddr + o->dataLen));
    uint32_t rcc = 0;
    for (const uint8_t* pData = data; pData != dataAddr + o->dataLen; pData++) {
        rcc += *pData;
    }
    if (rcc != rccRcv) {
        LOGCritcal("type[%u] RCC Error rcc[%u] vs rccRcv[%u]", o->type, rcc, rccRcv);
        return FRM_RCCERR;
    }

    return  FRM_OK;
}

void GenVerInfo(uint8_t* dst, size_t lenMax)
{
    if (dst == NULL || lenMax < 8) {
        return;
    }
    // example : 十进制下当前年月日时分秒
    // 20 22 06 18 07 57 59 00
    const char* date = __DATE__;
    // 年份
    uint16_t year = atoi(date + 7);
    dst[0] =  year / 100;
    dst[1] =  year % 100;
    // 月份
    switch (date[0]) {
        case 'J' : dst[2] = (date[1] == 'a' ? 1 : (date[2] == 'n' ? 6 : 7)); break; // Jan | Jun | Jul
        case 'F' : dst[2] = 2; break; // Feb
        case 'M' : dst[2] = (date[2] == 'r' ? 3 : 5); break; // Mar | May
        case 'A' : dst[2] = (date[2] == 'p' ? 4 : 8); break; // April | August
        case 'S' : dst[2] = 9; break; // Sep
        case 'O' : dst[2] = 10; break; // Oct
        case 'N' : dst[2] = 11; break; // Nov
        case 'D' : dst[2] = 12; break; // Dec
        default: dst[2] = 0;
    }
    // 日期
    dst[3] = atoi(date + 4);
    // 时间
    sscanf(__TIME__, "%hhu:%hhu:%hhu", &dst[4], &dst[5], &dst[6]);
}
